1 From fcd1c53b460aa39cfd15f842126af62b27a4fad5 Mon Sep 17 00:00:00 2001
2 From: Lei Wei <quic_leiwei@quicinc.com>
3 Date: Tue, 2 Apr 2024 18:28:42 +0800
4 Subject: [PATCH 13/50] net: pcs: Add 2500BASEX interface mode support to IPQ
7 2500BASEX mode is used when PCS connects with QCA8386 switch in a fixed
8 2500M link. It is also used when PCS connectes with QCA8081 PHY which
9 works at 2500M link speed. In addition, it can be also used when PCS
10 connects with a 2.5G SFP module.
12 Change-Id: I3fe61113c1b3685debc20659736a9488216a029d
13 Signed-off-by: Lei Wei <quic_leiwei@quicinc.com>
15 drivers/net/pcs/pcs-qcom-ipq-uniphy.c | 95 +++++++++++++++++++++++++++
16 1 file changed, 95 insertions(+)
18 --- a/drivers/net/pcs/pcs-qcom-ipq-uniphy.c
19 +++ b/drivers/net/pcs/pcs-qcom-ipq-uniphy.c
21 #define PCS_MODE_SGMII FIELD_PREP(PCS_MODE_SEL_MASK, 0x4)
22 #define PCS_MODE_QSGMII FIELD_PREP(PCS_MODE_SEL_MASK, 0x1)
23 #define PCS_MODE_PSGMII FIELD_PREP(PCS_MODE_SEL_MASK, 0x2)
24 +#define PCS_MODE_SGMII_PLUS FIELD_PREP(PCS_MODE_SEL_MASK, 0x8)
25 #define PCS_MODE_XPCS FIELD_PREP(PCS_MODE_SEL_MASK, 0x10)
26 #define PCS_MODE_AN_MODE BIT(0)
28 @@ -282,6 +283,24 @@ static void ipq_unipcs_get_state_sgmii(s
29 state->pause |= MLO_PAUSE_RX;
32 +static void ipq_unipcs_get_state_2500basex(struct ipq_uniphy_pcs *qunipcs,
34 + struct phylink_link_state *state)
38 + val = ipq_unipcs_reg_read32(qunipcs, PCS_CHANNEL_STS(channel));
40 + state->link = !!(val & PCS_CHANNEL_LINK_STS);
45 + state->speed = SPEED_2500;
46 + state->duplex = DUPLEX_FULL;
47 + state->pause |= MLO_PAUSE_TXRX_MASK;
50 static void ipq_unipcs_get_state_usxgmii(struct ipq_uniphy_pcs *qunipcs,
51 struct phylink_link_state *state)
53 @@ -373,6 +392,12 @@ static int ipq_unipcs_config_mode(struct
54 PCS_MODE_SEL_MASK | PCS_MODE_AN_MODE,
57 + case PHY_INTERFACE_MODE_2500BASEX:
59 + ipq_unipcs_reg_modify32(qunipcs, PCS_MODE_CTRL,
61 + PCS_MODE_SGMII_PLUS);
63 case PHY_INTERFACE_MODE_USXGMII:
64 case PHY_INTERFACE_MODE_10GBASER:
66 @@ -450,6 +475,22 @@ err:
70 +static int ipq_unipcs_config_2500basex(struct ipq_uniphy_pcs *qunipcs,
71 + phy_interface_t interface)
75 + if (qunipcs->interface != interface) {
76 + ret = ipq_unipcs_config_mode(qunipcs, interface);
80 + qunipcs->interface = interface;
86 static int ipq_unipcs_config_usxgmii(struct ipq_uniphy_pcs *qunipcs,
87 unsigned int neg_mode,
88 phy_interface_t interface)
89 @@ -522,6 +563,21 @@ static unsigned long ipq_unipcs_clock_ra
93 +static unsigned long ipq_unipcs_clock_rate_get_gmiiplus(int speed)
95 + unsigned long rate = 0;
108 static unsigned long ipq_unipcs_clock_rate_get_xgmii(int speed)
110 unsigned long rate = 0;
111 @@ -566,6 +622,9 @@ ipq_unipcs_link_up_clock_rate_set(struct
112 case PHY_INTERFACE_MODE_PSGMII:
113 rate = ipq_unipcs_clock_rate_get_gmii(speed);
115 + case PHY_INTERFACE_MODE_2500BASEX:
116 + rate = ipq_unipcs_clock_rate_get_gmiiplus(speed);
118 case PHY_INTERFACE_MODE_USXGMII:
119 case PHY_INTERFACE_MODE_10GBASER:
120 rate = ipq_unipcs_clock_rate_get_xgmii(speed);
121 @@ -627,6 +686,21 @@ pcs_adapter_reset:
122 PCS_CHANNEL_ADPT_RESET);
125 +static void ipq_unipcs_link_up_config_2500basex(struct ipq_uniphy_pcs *qunipcs,
129 + /* 2500BASEX do not support autoneg and do not need to
130 + * configure PCS speed, only reset PCS adapter here.
132 + ipq_unipcs_reg_modify32(qunipcs, PCS_CHANNEL_CTRL(channel),
133 + PCS_CHANNEL_ADPT_RESET,
135 + ipq_unipcs_reg_modify32(qunipcs, PCS_CHANNEL_CTRL(channel),
136 + PCS_CHANNEL_ADPT_RESET,
137 + PCS_CHANNEL_ADPT_RESET);
140 static void ipq_unipcs_link_up_config_usxgmii(struct ipq_uniphy_pcs *qunipcs,
143 @@ -669,6 +743,17 @@ static void ipq_unipcs_link_up_config_us
144 XPCS_USXG_ADPT_RESET);
147 +static int ipq_unipcs_validate(struct phylink_pcs *pcs,
148 + unsigned long *supported,
149 + const struct phylink_link_state *state)
151 + /* In-band autoneg is not supported for 2500BASEX */
152 + if (state->interface == PHY_INTERFACE_MODE_2500BASEX)
153 + phylink_clear(supported, Autoneg);
158 static void ipq_unipcs_get_state(struct phylink_pcs *pcs,
159 struct phylink_link_state *state)
161 @@ -682,6 +767,9 @@ static void ipq_unipcs_get_state(struct
162 case PHY_INTERFACE_MODE_PSGMII:
163 ipq_unipcs_get_state_sgmii(qunipcs, channel, state);
165 + case PHY_INTERFACE_MODE_2500BASEX:
166 + ipq_unipcs_get_state_2500basex(qunipcs, channel, state);
168 case PHY_INTERFACE_MODE_USXGMII:
169 ipq_unipcs_get_state_usxgmii(qunipcs, state);
171 @@ -716,6 +804,8 @@ static int ipq_unipcs_config(struct phyl
172 case PHY_INTERFACE_MODE_PSGMII:
173 return ipq_unipcs_config_sgmii(qunipcs, channel,
174 neg_mode, interface);
175 + case PHY_INTERFACE_MODE_2500BASEX:
176 + return ipq_unipcs_config_2500basex(qunipcs, interface);
177 case PHY_INTERFACE_MODE_USXGMII:
178 return ipq_unipcs_config_usxgmii(qunipcs,
179 neg_mode, interface);
180 @@ -748,6 +838,10 @@ static void ipq_unipcs_link_up(struct ph
181 ipq_unipcs_link_up_config_sgmii(qunipcs, channel,
184 + case PHY_INTERFACE_MODE_2500BASEX:
185 + ipq_unipcs_link_up_config_2500basex(qunipcs,
188 case PHY_INTERFACE_MODE_USXGMII:
189 ipq_unipcs_link_up_config_usxgmii(qunipcs, speed);
191 @@ -761,6 +855,7 @@ static void ipq_unipcs_link_up(struct ph
194 static const struct phylink_pcs_ops ipq_unipcs_phylink_ops = {
195 + .pcs_validate = ipq_unipcs_validate,
196 .pcs_get_state = ipq_unipcs_get_state,
197 .pcs_config = ipq_unipcs_config,
198 .pcs_link_up = ipq_unipcs_link_up,